﻿using System.Diagnostics.CodeAnalysis;
using Blazor.Util.Extension;
using Microsoft.Extensions.Logging;

namespace Blazor.Util;

public class SafeHttpClient(ILogger logger) : IDisposable
{
    private readonly HttpClient _client = new();

    private static async Task CheckStatusCode(HttpResponseMessage response, CancellationToken token)
    {
        if (!response.IsSuccessStatusCode)
        {
            var content = await response.Content.ReadAsStringAsync(token);
            throw new HttpRequestException($"Get error status code {response.StatusCode}: {content}");
        }
    }
    
    public async Task<HttpResponseMessage?> GetOrDefaultAsync([StringSyntax("Uri")] string? requestUri, CancellationToken token = default)
    {
        try
        {
            var response = await _client.GetAsync(requestUri, token);
            await CheckStatusCode(response, token);
            
            return response;
        }
        catch (OperationCanceledException e)
        {
            logger.LogWarning(e, "Cancelled get, uri: {0}", requestUri);
            return null;
        }
        catch (Exception e)
        {
            logger.LogException(e);
            return null;
        }
    }
    
    public async Task<HttpResponseMessage?> GetOrDefaultAsync(Uri? requestUri, CancellationToken token = default)
    {
        try
        {
            var response = await _client.GetAsync(requestUri, token);
            await CheckStatusCode(response, token);
            
            return response;
        }
        catch (OperationCanceledException e)
        {
            logger.LogWarning(e, "Cancelled get, uri: {0}", requestUri);
            return null;
        }
        catch (Exception e)
        {
            logger.LogException(e);
            return null;
        }
    }
    
    public async Task<HttpResponseMessage?> PutOrDefaultAsync(Uri? requestUri, HttpContent content, CancellationToken token = default)
    {
        try
        {
            var response = await _client.PutAsync(requestUri, content, token);
            await CheckStatusCode(response, token);
            
            return response;
        }
        catch (OperationCanceledException e)
        {
            logger.LogWarning(e, "Cancelled put, uri: {0}", requestUri);
            return null;
        }
        catch (Exception e)
        {
            logger.LogException(e);
            return null;
        }
    }

    public async Task<HttpResponseMessage?> DeleteOrDefaultAsync([StringSyntax("Uri")] string? requestUri, CancellationToken token = default)
    {
        try
        {
            var response = await _client.DeleteAsync(requestUri, token);
            await CheckStatusCode(response, token);
            
            return response;
        }
        catch (OperationCanceledException e)
        {
            logger.LogWarning(e, "Cancelled delete, uri: {0}", requestUri);
            return null;
        }
        catch (Exception e)
        {
            logger.LogException(e);
            return null;
        }
    }
    
    public async Task<HttpResponseMessage?> DeleteOrDefaultAsync(Uri? requestUri, CancellationToken token = default)
    {
        try
        {
            var response = await _client.DeleteAsync(requestUri, token);
            await CheckStatusCode(response, token);
            
            return response;
        }
        catch (OperationCanceledException e)
        {
            logger.LogWarning(e, "Cancelled delete, uri: {0}", requestUri);
            return null;
        }
        catch (Exception e)
        {
            logger.LogException(e);
            return null;
        }
    }
    
    public async Task<HttpResponseMessage?> PostOrDefaultAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, HttpContent? content, CancellationToken token = default)
    {
        try
        {
            var response = await _client.PostAsync(requestUri, content, token);
            await CheckStatusCode(response, token);
            
            return response;
        }
        catch (OperationCanceledException e)
        {
            logger.LogWarning(e, "Cancelled post, uri: {0}", requestUri);
            return null;
        }
        catch (Exception e)
        {
            logger.LogException(e);
            return null;
        }
    }
    
    public async Task<HttpResponseMessage?> PostOrDefaultAsync(Uri? requestUri, HttpContent? content, CancellationToken token = default)
    {
        try
        {
            var response = await _client.PostAsync(requestUri, content, token);
            await CheckStatusCode(response, token);
            
            return response;
        }
        catch (OperationCanceledException e)
        {
            logger.LogWarning(e, "Cancelled post, uri: {0}", requestUri);
            return null;
        }
        catch (Exception e)
        {
            logger.LogException(e);
            return null;
        }
    }

    public void Dispose()
    {
        _client.Dispose();
    }
}